﻿/*
Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/

(function () {
	(function () {
		var tagRegExp = /<[^>]*>/g;
		var lastRange = null;
		this.keys = null;
		this._obj = null;
		this.init = _init;
		this.input = _input;
		this.keyup = _keyup;
		this.paste = _paste;
		this.addEvent = _addEvent;
		this.removeEvent = _removeEvent;
		this.click = _click;
		this._document = document;
		this._window = window;
		this.replaceKeys = _replaceKeys;
		this.clearFormat = _clearFormat;
		this.clearColor = _clearColor;
		this.setKeys = _setKeys;
		this.highLights = [];
		this.editor = null;
		this.attachCount = 0;
		this.path = null;
		var _this = this;
		this.setHighLight = function (objId) {
			if (this.keys == null || this.keys == undefined) { alert("高亮JS尚未设置关键字"); return; }

			this._obj = $(objId);
			if (arguments.length == 2) {
				_this._window = arguments[1];
				_this._document = _this.window.document;
			}
			this.init();
			this.addEvent(_this._obj, "keyup", this.keyup);
			this.addEvent(_this._obj, "click", this.click);
			this.addEvent(_this._document, "paste", this.paste);
		}
		this.__setHighList_CKEDITOR = function (editor) {
			if (!editor.window || !editor.window.$) { return; }
			_this._window = editor.window.$;
			_this._document = editor.document.$;
			_this._obj = $(_this._document.body);
			_this.editor = editor;
			_this.attachCount = 0;
			_this.init();
			_this._document.body.focus();


			if (CKEDITOR.env.webkit) {
				_this.removeEvent(_this._obj, "input", _this.keyup);
				_this.addEvent(_this._obj, "input", _this.keyup);
			} else {
				_this.removeEvent(_this._obj, "keyup", _this.keyup);
				_this.addEvent(_this._obj, "keyup", _this.keyup);
			}
			_this.removeEvent(_this._obj, "click", _this.click);
			_this.addEvent(_this._obj, "click", _this.click);
			if (this.attachCount == 0) {
				_this.editor.on("paste", _this.paste);
				_this.editor.on("mode", function () {
					if (_this.editor.mode != "source") {
						setTimeout(function () {
							_this.init();
						}, 100);
					}
				});
			}
			_this.attachCount++;
		}
		this.setHighLight_CKEDITOR = function () {
			try {
				if (!window.CKEDITOR || !window.CKEDITOR.instances) { return; }

				var arr = [];
				if (arguments.length == 1) {
					arr.push(arguments[0]);
				}
				else {
					for (var i in CKEDITOR.instances) {
						arr.push(CKEDITOR.instances[i]);
					}
				}
				for (var i in arr) {
					var editor = arr[i];
					var _lightObj = _this._extend({}, _this);
					_lightObj.__setHighList_CKEDITOR(editor);
					this.highLights.push(_lightObj);
				}
			} catch (ex) {
			}
		}
		function _setKeys(keyArr) {
			if (keyArr instanceof Array) {
				this.keys = keyArr;
				for (var i = 0; i < this.keys.length; i++) {
					var key = this.keys[i];
					if (key.Key == ' ') {
						key.regexp = new RegExp(" {1}|&nbsp;{1}", "gi");
					} else {
						key.regexp = new RegExp(key.Key.replace(/\*/gi, '.*?').replace(/\?/gi, '.{1}'), "gi");
					}
				}
			}
		}
		this._extend = extend;
		function extend(destination, source) {
			for (var property in source) {
				try {
					destination[property] = source[property];
				} catch (e) { }
			}
			return destination;
		}
		function _init() {
			try {
				var html = _this._document.body.innerHTML;
				html = _replaceKeys(_clearColor(html));
				//                var brImg = getBrSpanHTML();
				//                if (html.toLowerCase().indexOf("\"brset\"") == -1) {
				//                    html = html.replace(/<br\s*\/?>/gi, brImg + "<br />");
				//                }
				_this._document.body.innerHTML = html;
				_this._document.body.focus();
				var range = new CKEDITOR.dom.range(editor.document);
				var last = editor.document.getBody().getLast();
				if (last) {
					range.setStartAfter(last);
					range.setEndAfter(last);

				} else {
					range.setStart(editor.document.getBody(), 0);
					range.setEnd(editor.document.getBody(), 0);
				}
				range.select();
			} catch (ex) { }
		}
		function isColorSpan(obj) {
			if (!obj || obj.tagName == undefined) { return false; }
			if (obj.tagName == "SPAN" && obj.getAttribute("mc") == "colorSet") {
				return true;
			}
			return false;
		}
		function isCkColorSpan(obj) {
			if (isColorSpan(obj.$)) {
				return true;
			}
			var parentList = obj.getParents();
			for (var i = 0; i < parentList.length; i++) {
				var _node = parentList[i];

				if (isColorSpan(_node.$)) {
					return true;
				}
			}
			return false;
		}
		function replaceByHtml(node, html, ckdoc) {
			var span = CKEDITOR.dom.element.createFromHtml("<span>" + html + "</span>", ckdoc);
			span.insertBefore(node);
			node.remove();
			var nodeList = span.getChildren();
			var nNode;
			for (var i = nodeList.count() - 1; i >= 0; i--) {
				nNode = nodeList.getItem(i);
				nNode.insertAfter(span);
			}
			span.remove();
		}
		function createTag() {
			var id = "mytag";
			if (arguments.length > 0) { id = "posTag"; }
			return "<span id=\"" + id + "\">*</span>";
		}
		function createTagSpan() {
			var html = createTag(1);
			var span = CKEDITOR.dom.element.createFromHtml(html, _this.editor.document);
			return span;
		}
		function getTagElement(ckDoc) {
			return ckDoc.getById('posTag');
		}
		function moveToTag(range) {
			var tagElement = getTagElement(range.document);
			range.moveToPosition(tagElement, 4);
			_this.editor.getSelection().selectRanges([range]);
			tagElement.remove();
		}
		function insertTagToHtml(html, position) {
			html = html.replace("?", "");
			var arrPos = 0;
			var pos = 0;
			var currentPos = 0;
			var arr = splitColorSet(html);
			var found = false;
			for (var i = 0; i < arr.length; i++) {
				if (arr[i].indexOf("<span") != -1 || arr[i].indexOf("</span") != -1) {
					continue;
				}
				currentPos += arr[i].length;
				if (position <= currentPos && position > (currentPos - arr[i].length)) {
					pos = position - currentPos + arr[i].length;
					arrPos = i;
					found = true;
					break;
				}
			}
			if (!found) {
				for (var i = arr.length - 1; i >= 0; i--) {
					if (arr[i].indexOf("<span") != -1 || arr[i].indexOf("</span") != -1) {
						continue;
					}
					pos = arr[i].length;
					arrPos = i;
					break;
				}
			}
			arr[arrPos] = _insertTag(arr[arrPos], pos);
			var ret = arr.join('');
			return ret;
			function _insertTag(_html, _position) {
				if (_position > _html.length) {
					_position = _html.length;
				}
				var s1 = _html.substr(0, _position);
				var s2 = _html.substr(_position);
				var tag = createTag(1);
				return s1 + tag + s2;
			}
		}
		//创建颜色span对象
		function createColorSpan() {
			var n = _this._document.createElement("SPAN");
			n.setAttribute("mc", "colorSet");
			return n;
		}
		//创建颜色span HTML
		function createColorSpanHTML(key, content) {
			return "<span style=\"background-color:" + key.BackColor + ";color:" + (key.ForeColor ? key.ForeColor : '#fff') + ";\" mc=\"colorSet\" data-highlight-sug=\"" + key.Suggest + "\">" + content + "</span>";
		}
		function createBrSpan(ckdoc) {
			return CKEDITOR.dom.element.createFromHtml(getBrSpanHTML(), ckdoc)
		}
		function getBrSpanHTML() {
			return "<img mc=\"brSet\" src=\"" + _this.path + "images/br.gif\"></img>";
		}
		//将颜色span拆份为数组，为插入标志做准备
		function splitColorSet(s) {
			var re = /<span.*?mc\=\"colorSet\".*?>/gi;
			var re1 = /<\/span>/gi;
			var foundEndSpan = false;
			var foundStartSpan = false;
			if (/<\/span>$/i.test(s)) {
				s += " ";
				foundEndSpan = true;
			}
			if (s.toLowerCase().indexOf("<span") == 0) {
				s = " " + s;
				foundStartSpan = true;
			}
			var myarr = [];
			var _arr = splitByRegex(s, re);
			for (var i in _arr) {
				var __arr = splitByRegex(_arr[i], re1);
				for (var j in __arr) {
					if (__arr[j] == undefined || __arr[j] == "") {
						continue;
					}
					myarr.push(__arr[j]);
				}
			}
			if (foundEndSpan) {
				myarr.pop();
			}
			if (foundStartSpan) {
				var arr = [];
				if (myarr.length > 1) {
					for (var i = 1; i < myarr.length; i++) {
						arr.push(myarr[i]);
					}
				}
				myarr = arr;
			}
			return myarr;

			function splitByRegex(s, re) {
				var arr = [];
				if (s == undefined) { arr.push(""); return arr; }
				var arr1 = s.split(re);

				if (arr1.length == 1) {
					arr.push(s);
					return arr;
				}
				var marr = s.match(re);
				for (var i = 0; i < arr1.length; i++) {
					arr.push(arr1[i]);
					if (i < arr1.length) {
						arr.push(marr[i]);
					}
				}
				return arr;
			}
		}
		//等于document.getElementById
		function $(objId) {
			if (objId) {
				if (typeof objId === "string") {
					return this.document.getElementById(objId);
				}
				if (typeof objId === "object") {
					return objId;
				}
			}
			return null;
		}
		var tmObj = null;
		function keyUp(e) {
			/*
			function replaceBR() {
			var ret = false;
			//处理br
			function brHasPreImg(br) {
			var preNode = br.getPrevious();
			var count = 0;
			while (preNode && preNode.type == 3 && preNode.getText() == "") {
			preNode = preNode.getPrevious();
			count++;
			}
			if (preNode) {
			if (count < 2 && isBrSet(preNode)) {
			return preNode;
			}
			}
			return null;
			}
			//判断
			function isBrSet(br) {
			var ret = false;
			if (br.$ && br.$.tagName == "IMG" && br.$.getAttribute("mc").toLowerCase() == "brset") {
			ret = true;
			}
			return ret;
			}
			var sec = _this.editor.getSelection();
			var rgs = sec.getRanges();
			if (rgs.length == 0) {
			return;
			}
			rg = rgs[0];
			var secNode = null;
			if (rg.startContainer.type == 3) {
			//console.log("startOffset:",rg.startOffset);
			var preImgNode = brHasPreImg(rg.startContainer);
			if (preImgNode) {
			//如果前一个节点为换行符则删除掉
			//console.log("prenodeIsimg:","yes");
			preImgNode.remove();
			}
			else if (rg.startOffset == 0) {
			//光标在文本节点第0个字符时可能前一个节点为换行符
			var foundWay = -1;
			if (CKEDITOR.env.webkit) {
			var _node = rg.startContainer.getPrevious();
			if (_node) {
			secNode = _node.getPrevious();
			if (secNode && secNode.$ && secNode.$.tagName == "BR") {
			foundWay = 0;
			}
			}
			if (foundWay == -1) {
			_node = rg.startContainer.getNext();
			if (_node) {
			secNode = _node.getNext();
			if (secNode && secNode.$ && secNode.$.tagName == "BR") {
			foundWay = 1;
			}
			}
			}
			} else {
			secNode = rg.startContainer.getPrevious();
			if (secNode && secNode.$ && secNode.$.tagName == "BR") {
			foundWay = 0;
			}
			if (foundWay == -1) {
			secNode = rg.startContainer.getNext();
			if (secNode && secNode.$ && secNode.$.tagName == "BR") {
			foundWay = 1;
			}
			}
			}
			//console.log("foundWay:",foundWay);
			//console.log("rg.startContainer:",rg.startContainer.getText());

			if (foundWay == 0) {
			var preImg = null;
			if (!(preImg = brHasPreImg(secNode))) {
			//console.log("startOffset",rg.startOffset);
			var brSpan = createBrSpan(rg.document);
			brSpan.insertBefore(secNode);
			rg.setStartAfter(brSpan);
			rg.collapse();
			sec.selectRanges([rg]);
			//console.log("insertBrImg","yes");
			}
			} else if (foundWay == 1) {
			var preImg = null;
			if (!(preImg = brHasPreImg(secNode))) {
			secNode.remove();
			//console.log("RemoveBR","yes");
			}
			}
			}
			} else {
			//初始换行，没有后续节点时
			//console.log("2startOffset:",rg.startOffset);					
			var _si = 1;
			if (CKEDITOR.env.webkit) { _si = 0; }
			var childlist = rg.startContainer.getChildren();
			var preNode = childlist.getItem(rg.startOffset - _si - 1);
			var nextNode = childlist.getItem(rg.startOffset - _si + 1);
			var secNode = childlist.getItem(rg.startOffset - _si);
			var prepreNode = preNode ? preNode.getPrevious() : null;
			//if(prepreNode) //console.log("prepreNode:",prepreNode.$.tagName+"_"+prepreNode.getText());
			//if(preNode) //console.log("preNode:",preNode.$.tagName+"_"+preNode.getText());
			//if(secNode) //console.log("secNode:",secNode.$.tagName+"_"+secNode.getText());
			//if(nextNode) //console.log("nextNode:",nextNode.$.tagName+"_"+nextNode.getText());
			if (secNode && secNode.$.tagName == "BR") {
			//正常换行		
			//console.log("正常换行:","YES");						
			if (secNode) {
			var _node = secNode;
			var _count = 0;
			while (_node && _node.$ && _node.$.tagName == "BR" && (!brHasPreImg(_node))) {
			var brSpan = createBrSpan(rg.document);
			var iNode = _node;
			if (CKEDITOR.env.webkit) {
			var _i = 0;
			var _foundCorrect = false;
			while (true) {
			if (_i > 2) { break; }
			iNode = iNode.getPrevious();
			if (!iNode) { break; }
			if (iNode.$.tagName == "BR") { _foundCorrect = true; break; }
			_i++;
			}
			if (!_foundCorrect) { iNode = null; }
			}
			if (!iNode) { break; }
			brSpan.insertBefore(iNode);
			_node = brSpan.getPrevious();
			_count++;
			}
			//console.log("count:",_count);
			}
			if (nextNode && nextNode.$.tagName == "BR") {
			nextNode.remove();
			}
			}
			else if (secNode && isBrSet(secNode)) {
			secNode.remove();
			}
			else if (preNode && nextNode && isBrSet(preNode)) {
			//在换行符号后插入
			//console.log("isBrAfter:","yes");
			var cutNode = secNode.clone();
			var insertNode = nextNode;
			if (isBrSet(nextNode)) { insertNode = nextNode.getNext(); }
			nextNode.remove();
			cutNode.insertAfter(insertNode);
			secNode.remove();
			rg.selectNodeContents(cutNode);
			rg.collapse(false);
			sec.selectRanges([rg]);
			}
			else if (nextNode && nextNode.$.tagName == "BR") {
			//换行符号被删除,这时应该连换行符一起删除
			//console.log("nextNodeIsBR:","yes");
			nextNode.remove();
			}
			}
			return ret;
			};

			if (replaceBR()) { return; }
			*/

			//关键词替换
			try {
				if (CKEDITOR.env.webkit) {
					setTimeout(function () { a(); }, 200);
				}
				else {
					a();
				}
			} catch (ex) { }
			function replaceText(rg) {
				var sNode = rg.startContainer;
				var text = sNode.getText();
				var pos = rg.startOffset;
				var txtArr = [];
				var txtArr1 = [];
				var startNode = null;
				var endNode = null;
				nNode = sNode.getPrevious();
				var nodeList1 = [];
				var nodeList2 = [];
				while (nNode && (nNode.type == 3 || nNode.getParent().$.tagName == "FONT")) {
					txtArr.push(nNode.getText());
					nodeList1.push(nNode);
					nNode = nNode.getPrevious();
				}
				nNode = sNode.getNext();
				while (nNode && (nNode.type == 3 || nNode.getParent().$.tagName == "FONT")) {
					txtArr1.push(nNode.getText());
					nodeList2.push(nNode);
					nNode = nNode.getNext();
				}


				txtArr = txtArr.reverse();
				var str1 = txtArr.join('');
				var str2 = text;
				var str3 = txtArr1.join('');
				text = str1 + str2 + str3;
				var text2 = _replaceKeys(text);
				if (text == text2) return;

				sNode.remove();
				for (var i in nodeList1) {
					nodeList1[i].remove();
				}
				for (var i in nodeList2) {
					nodeList2[i].remove();
				}


				var newPos = str1.length + pos;
				text = text2;

				text = insertTagToHtml(text, newPos);


				var sec = _this.editor.getSelection();
				var rgs = sec.getRanges();
				if (rgs.length == 0) {
					return;
				}
				var rg = rgs[0];
				var span = createTagSpan();
				rg.insertNode(span);
				replaceByHtml(span, text, rg.document);
				moveToTag(rg);
			}
			function a() {
				var sec;
				var rg;

				sec = _this.editor.getSelection();
				var rgs = sec.getRanges();
				if (rgs.length == 0) {
					return;
				}
				rg = rgs[0];
				if (rg.collapsed) {
					var selfNode = rg.startContainer;
					var _isColorSpan = false;
					var _isFont = false;
					var parentList = selfNode.getParents();
					var matchNode = null;

					for (var i = 0; i < parentList.length; i++) {
						var _node = parentList[i];
						if (isColorSpan(_node.$)) {
							_isColorSpan = true;
							matchNode = _node;
							break;
						}
					}

					var parentNode = selfNode.getParent();
					if (!_isColorSpan && parentNode && parentNode.$ && parentNode.$.tagName == "FONT" && parentNode.$.getAttribute("color") == "#ffffff") {
						_isFont = true;
					}
					if (_isFont) {
						//console.log("isFont","true");
						replaceByHtml(parentNode, parentNode.getText(), rg.document);
						var sec = _this.editor.getSelection();
						var rgs = sec.getRanges();
						if (rgs.length == 0) {
							return;
						}
						var rg = rgs[0];
						replaceText(rg);
					}
					else if (_isColorSpan) {
						//console.log("_isColorSpan","true");
						var text = matchNode.getText();
						//console.log("text:",text);
						text = _replaceKeys(matchNode.getText(), function (_m) {
							m = _m;
						});
						var newPos = rg.startOffset;
						//console.log("startOffset:",newPos);
						//console.log("startContainer:",rg.startContainer.getText());
						//console.log("startContainer_type:",rg.startContainer.type);
						if (rg.startContainer.type == 3) {
							var cParent = rg.startContainer.getParent();
							var childList = cParent.getChildren();
							//console.log("childList.length",childList.count());
							var cIndex = rg.startContainer.getIndex();
							for (var _i = 0; _i < cIndex; _i++) {
								newPos += childList.getItem(_i).getText().length;
							}
						}
						else {
							newPos = rg.startContainer.getText().length;
						}

						//console.log("text:",text);
						//console.log("newPos:",newPos);
						text = insertTagToHtml(text, newPos);
						//console.log("text:",text);
						replaceByHtml(matchNode, text, rg.document);
						moveToTag(rg);
					}
					else if (selfNode.type == 3) {
						//console.log("replaceText:","true");
						replaceText(rg);
						var preNode = selfNode.getPrevious();
						while (preNode && preNode.getText() == "") {
							preNode = preNode.getPrevious();
						}
						var needFix = false;
						var preText = "";
						if (preNode) {
							if (preNode.type != 3 && isColorSpan(preNode.$)) {
								preText = preNode.getText();
								if (_replaceKeys(preText) == preText) {
									needFix = true;
								}
							}
						}
						if (needFix) {
							//console.log("needFix","true");
							replaceByHtml(preNode, preNode.getText(), rg.document);
							var sec = _this.editor.getSelection();
							var rgs = sec.getRanges();
							if (rgs.length == 0) {
								return;
							}
							var rg = rgs[0];
							replaceText(rg);
						}
					}
				}
			}
		}

		function _keyup(e) {
			if (e.shiftKey || e.keyCode == 16) { e.preventDefault ? e.preventDefault() : 0; return true; }
			if (e.keyCode == 67) { e.preventDefault ? e.preventDefault() : 0; return; }
			if (e.keyCode >= 37 && e.keyCode <= 40) { e.preventDefault ? e.preventDefault() : 0; return true; }
			if (e.ctrlKey && (e.keyCode == 90 || e.keyCode == 32)) { e.preventDefault ? e.preventDefault() : 0; return true; }
			if (e.keyCode == 17) { e.preventDefault ? e.preventDefault() : 0; return true; }
			keyUp(e);
		}
		function _click(e) {
			try {
				var s = e.target.ownerDocument.getSelection();
				lastRange = s.getRangeAt(0);
			} catch (e) { }
		}
		function _replaceKeys(_str) {

			var str = _str;
			var matchNum = 0;
			if (str == null || str == undefined) return "";
			var firstIndex = 0;
			var firstSize = 0;
			var isSetFirst = false;
			for (var _key in keys) {
				key = keys[_key];
				str = _replaceHTMLContent(str, key.regexp, function ($0) {
					isMatch = true;
					matchNum++;
					if (!isSetFirst) {
						firstIndex = _str.indexOf($0);
						firstSize = $0.length;
						isSetFirst = true;
					}
					return createColorSpanHTML(key, $0);
				});
			}
			if (arguments.length > 1 && typeof (arguments[1]) == "function") {
				arguments[1].call(null,
				{
					"matchNum": matchNum,
					"firstIndex": firstIndex,
					"firstSize": firstSize
				})
			}
			return str;
		}
		function _replaceHTMLContent(html, key, replacer) {
			var contents = [];
			var lastIndex = 0;
			while ((match = tagRegExp.exec(html)) != null) {
				if (lastIndex < match.index) {
					contents.push(html.slice(lastIndex, match.index).replace(key, replacer));
				}
				contents.push(match[0]);
				lastIndex = match.index + match[0].length;
			}
			if (lastIndex < html.length) {
				contents.push(html.slice(lastIndex).replace(key, replacer));
			}
			return contents.join('');
		}

		function _clearFormat(str) {
			if (str == null || str == undefined) return "";
			var re = /<br.*?\/?>/gi;
			str = str.replace(re, "[br]");
			re = /<(.*)[^>]*>(.*)<\/\1>/gi;
			str = str.replace(re, function ($0, $1, $2) {
				if ($1.toLowerCase() == "img") { return $0; }
				if ($1.toLowerCase() == "strong") { return $2; }
				return "<" + $1 + ">" + $2 + "<" + $1 + "/>";
			});
			str = str.replace(/\[br\]/gi, "<br />");
			return str;
		}
		function _clearColor() {
			var html = arguments.length == 1 ? arguments[0] : _this._document.body.innerHTML;
			var regex = /<span.*?mc=\"colorSet\".*?>(.*?)<\/span>/gi;
			html = html.replace(regex, function ($0, $1) {
				return $1;
			});
			if (arguments.length == 1) { _this._document.body.innerHTML = html; }
			return html;
		}
		function _input(e) {
			var s = _this._window.getSelection();
			var _rg = s.getRangeAt(0);
			lastRange = _rg;
			var count = 0;
			function a() {
				var _rg = s.getRangeAt(0);
				var _ini_startOffset = _rg.startOffset;
				var _Expand = 0;
				var parentNodeIsNeedReplace = false;
				var isToSpan = false;
				if (isColorSpan(_rg.startContainer.parentNode)) {
					_Expand = _rg.startContainer.parentNode.textContent.length - _rg.endOffset;
					_rg.selectNode(_rg.startContainer.parentNode);
					parentNodeIsNeedReplace = true;
				} else {
					if (_rg.endContainer.previousSibling && _rg.endContainer.previousSibling.tagName == "#text") {
						_rg.setStart(_rg.endContainer.previousSibling, 0);
					}
					else {
						_rg.setStart(_rg.endContainer, 0);
						isToSpan = true;
					}
					var isExpand = false;
					if (_rg.endContainer.nextSibling && _rg.endContainer.nextSibling.tagName == "#text") {
						_rg.setEnd(_rg.endContainer.nextSibling, _rg.endContainer.nextSibling.textContent.length);
						_Expand = 1;
					}
					else {
						_rg.setEnd(_rg.endContainer, _rg.endContainer.textContent.length);
						isToSpan = isToSpan && true;
					}
				}
				var str = _rg.toString();
				var regex = /([a-z]{1,4})$/gi;
				if (regex.test(str)) {
					if (count == 0) {
						setTimeout(a, 3000);
						return;
					}
					count++;
				}
				var isMatch = false;
				var len_1 = str.length;
				str = _this.clearFormat(str);
				str = _this.replaceKeys(str);
				var len_2 = str.length;
				if (len_1 != len_2) { isMatch = true; isToSpan = isToSpan && true }
				if (isMatch || parentNodeIsNeedReplace) {
					_rg.deleteContents();
					var newNode = _rg.createContextualFragment(str);
					_rg.insertNode(newNode);
					_rg.collapse(false);
					if (isToSpan) {
						s.collapse(_rg.startContainer.childNodes[_rg.startOffset - _Expand - 1].firstChild, _ini_startOffset);
					}
					else {
						var _setOffset = 1;
						if (parentNodeIsNeedReplace) {
							_setOffset += 1;
						}
						s.collapse(_rg.startContainer.childNodes[_rg.startOffset - _Expand], _setOffset);
					}
					lastRange = s.getRangeAt(0);
				}
			}
			setTimeout(a, 100);
		}
		function _paste(e) {
			if (e.data && e.data.html) {
				var sec = _this.editor.getSelection();
				var rgs = sec.getRanges();
				if (rgs.length == 0) {
					return;
				}
				var rg = rgs[0];

				var html = e.data.html;
				html = _clearFormat(html);
				html = _replaceKeys(html);
				var brImg = getBrSpanHTML();
				html = html.replace(/<br\s*\/?>/gi, brImg + "<br />");
				e.data.html = html;
				setTimeout(function () { keyUp(); }, 10);
			}
		}
		function _addEvent(element, ev, func) {
			if (element.addEventListener) {
				element.addEventListener(ev, func, false);
			}
			else {
				element.attachEvent('on' + ev, func);
			}
		}
		function _removeEvent(element, ev, func) {
			if (element.removeEventListener) {
				element.removeEventListener(ev, func, false);
			}
			else {
				element.detachEvent('on' + ev, func);
			}
		}
		this.window.highlight = this;
	})();
	// Context menu constructing.
	var addButtonCommand = function (editor, buttonName, buttonLabel, commandName, command, menugroup, menuOrder) {
		editor.addCommand(commandName, command);

		// If the "menu" plugin is loaded, register the menu item.
		editor.addMenuItem(commandName,
			{
				label: buttonLabel,
				command: commandName,
				group: menugroup,
				order: menuOrder
			});
	};

	CKEDITOR.plugins.add('highlight', {
		requires: ['tabletools'],
		beforeInit: function (editor) {
			editor.config.menu_groups = 'highlight_suggest,' + editor.config.menu_groups;
		},
		init: function (editor) {
			// 当文本粘帖到编辑器中，删除 span[data-scaytid]
			highlight.path = this.path;
			var pName = 'highlight';
			var dataFilter = editor.dataProcessor && editor.dataProcessor.dataFilter;
			var dataFilterRules = {
				elements: {
					span: function (element) {
						var attrs = element.attributes;
						if (attrs && attrs['mc'])
							delete element.name;
					},
					img: function (element) {
						if (element.attributes['mc']) {
							delete element.name;
						}
					}
				}
			};
			dataFilter && dataFilter.addRules(dataFilterRules);
			editor.on('contentDom', function () {
				highlight.setKeys(editor.config.highLightKeys);
				highlight.__setHighList_CKEDITOR(editor);
			});

			editor.addCommand('resethighLightKeys', {
				modes: { wysiwyg: 1 },
				editorFocus: false,
				exec: function (editor) {
					highlight.clearColor();
					highlight.setKeys(editor.config.highLightKeys);
					highlight.__setHighList_CKEDITOR(editor);
				}
			});
			editor.addCommand('clearHighLight', {
				modes: { wysiwyg: 1 },
				editorFocus: false,
				exec: function (editor) {
					highlight.clearColor();
				}
			});
			var mainSuggestions = {};
			if (editor.contextMenu && editor.addMenuItems) {
				editor.contextMenu.addListener(function (element, selection) {
					if (!element || !element.getAttribute('data-highlight-sug'))
						return null;

					// Remove unused commands and menuitems
					for (m in mainSuggestions) {
						delete editor._.menuItems[m];
						delete editor._.commands[m];
					}
					mainSuggestions = {};

					var items_suggestion = element.getAttribute('data-highlight-sug') || '';
					items_suggestion = items_suggestion.split('|');
					//editor.addMenuGroup('highlight_suggest');
					for (var i = 0, l = items_suggestion.length; i < l; i += 1) {
						var commandName = 'highlight_suggestion_' + items_suggestion[i].replace(' ', '_');
						var exec = (function (el, s) {
							return {
								exec: function () {
									var text = new CKEDITOR.dom.text(s, editor.document);
									text.replace(el);
								}
							};
						})(element, items_suggestion[i]);

						addButtonCommand(editor, 'button_' + commandName, items_suggestion[i],
									commandName, exec, 'highlight_suggest', i + 1);
						mainSuggestions[commandName] = CKEDITOR.TRISTATE_OFF;
					}
					return mainSuggestions;
				});
			}

			var dataProcessor = editor.dataProcessor,
			htmlFilter = dataProcessor && dataProcessor.htmlFilter;

			if (htmlFilter) {
				htmlFilter.addRules({
					elements: {
						span: function (element) {
							if (element.attributes['mc']) {
								delete element.name; // Write children, but don't write this node.
								return element;
							}
						},
						img: function (element) {
							if (element.attributes['mc']) {
								delete element.name;
								return element;
							}
						}
					}
				}
			);
			}
		},
		afterInit: function (editor) {
			// 防止标记在清除格式时被删除
			var elementsPathFilters,
					filter = function (element) {
						if (element.hasAttribute('mc'))
							return false;
					};

			if (editor._.elementsPath && (elementsPathFilters = editor._.elementsPath.filters))
				elementsPathFilters.push(filter);
			editor.addRemoveFormatFilter && editor.addRemoveFormatFilter(filter);
		}
	});
})();
